 package cuShapes;

import java.awt.Color;
import xml.*;

import javax.swing.event.EventListenerList;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;

import actionHandlers.CurrentShapeListener;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import actionHandlers.PQShapeListener;

@XmlTransient
public abstract class PQShape {
	
	// produce a wrapper XML element around this collection
	@XmlJavaTypeAdapter(value=LinesAdapter.class)
	// maps each member of this list to an XML element named appointment
	@XmlElement(name = "lineslist")
	protected ArrayList<PQLine> lines;
	@XmlJavaTypeAdapter(ColorAdapter.class)
	@XmlAttribute
	protected Color color;
	@XmlAttribute(required=true)
	protected String name;
	
	@XmlJavaTypeAdapter(RectangleAdapter.class)
	@XmlElement
	protected Rectangle center, resize, rect;
	@XmlTransient
	protected Rectangle workingRect;
	@XmlElement
	protected int width, height;
	
	@XmlTransient
	protected EventListenerList listenerList;

	/**********************************
	 * Constructor. 
	 */
	protected PQShape () {
		lines = new ArrayList<PQLine>();
		color = Color.black;
		listenerList = new EventListenerList();
		this.addPQShapeListener(new CurrentShapeListener());
	}
	
	/***********************************
	 * 
	 * @return the list of lines that 
	 *    makes the shape
	 */
	public List<PQLine> getLineList() {
		if (lines == null) {
            lines = new ArrayList<PQLine>();
        }
        return this.lines;
	}
	

	@Override
	public String toString() {		
		return this.name;
	}
	
	public void setSelected(boolean bool) {
		if(bool)
			this.firePQShapeEvent(PQShapeEvent.PQSHAPE_FOCUSED);
		else
			this.firePQShapeEvent(PQShapeEvent.PQSHAPE_UNFOCUSED);
	}
	

    protected void firePQShapeEvent(int id) {  
          Object[] listeners = listenerList.getListenerList();
          PQShapeEvent e = null;
          for (int i = listeners.length -2; i >=0; i -= 2) {
        	  if (listeners[i] == PQShapeListener.class) {
        		  if (e == null) { 
        			  e = new PQShapeEvent(this, id);
        		  }
        		  
        		  switch(e.getID()) {
        		  case PQShapeEvent.PQSHAPE_FOCUSED:
        			  ((PQShapeListener)listeners[i+1]).PQShapeSelected(e);
        			  break;
        		  case PQShapeEvent.PQSHAPE_UNFOCUSED:
        			  ((PQShapeListener)listeners[i+1]).PQShapeDeselected(e);
        			  break;
        		  case PQShapeEvent.PQSHAPE_PROPERTY_CHANGED:
        			  ((PQShapeListener)listeners[i+1]).PQShapePropertyChanged(e);
        			  break;
        		  default:
        			  break;
        		  }
        	  }
          }
    }
	// by default PQShape is initialized with a PQShapeListener
	public void addPQShapeListener(PQShapeListener l) {
		listenerList.add(PQShapeListener.class, l);
		//enableEvents(0);
	}
	/***********************************
	 *  Draws each of the lines in the 
	 *    line list, applies the name
	 *    and fills the center and resize
	 *    rects.  
	 * @param g2
	 */
	public void drawToCanvas(Graphics2D g2) {
		for (PQLine line : lines) {
			line.drawLine(g2);
		}

		g2.drawString(name, center.x-14, resize.y-10);
		//g2.setColor(new Color(255,255,255));
		//g2.fill(rect);
		g2.setColor(new Color(0,0,0,75));
		g2.fill(center);
		g2.fill(resize);
	}
	

	
	/* Getters */
	public Color 		getColor(){ 		return this.color; }
	public String 		getName(){ 			return this.name; }
	public Rectangle 	getRect(){			return this.rect;	}
	public Rectangle 	getCenterRect(){	return this.center;	}
	public Rectangle	getWorkingRect(){	return this.workingRect; }
    public Point 		getStart() {		return lines.get(0).getStart();	}   
    public Point 		getEnd() {			return lines.get(0).getEnd();	}
	
	/* Setters */
	public void setWorkingRect(Rectangle r){ workingRect = r; }
		
	/*  Abstract Methods */
    public void setStart(Point start) {
    	this.firePQShapeEvent(PQShapeEvent.PQSHAPE_PROPERTY_CHANGED);
    }
    public void setEnd(Point end) {
    	this.firePQShapeEvent(PQShapeEvent.PQSHAPE_PROPERTY_CHANGED);
    }
    
	public abstract void moveWorkingRect(Point p);
	public abstract boolean hitRect(Point p);
    
    public abstract int getWidth();
    public abstract int getHeight();

    public abstract String getShapeClass();
    
    	
}
